#include "TDA_expresion.h"
#include <stdio.h>

/* El que hizo esta funcion, podria comentarla? Porque no entiendo muy bien lo que hace.
O sea si lo que hace, pero que hace en cada case, cuando vuelve a llamarse a si misma, etc */
int insertarSufijo(TAB ab,TLiteral lit)
{
    TLiteral litcte;
    int error,cambiorama;

    AB_ElemCte(ab,&litcte); /*obtiene el elemento corriente*/

    switch(Literal_EsOperador(&litcte)) /*dependiendo del tipo literal:*/
    {
        case 0: return 1; /*si es cero es una constante o una variable entonces no se tiene que mover m�s en el arbol*/
                break;

        case 1: AB_MoverCte(&ab,DER,&error); /*si es uno es un operador unario trata de moverse a la derecha*/
                if (error) /*si no pudo moverse lo inserta a la derecha del cte*/
                {
                    AB_Insertar(&ab,DER,&lit,&error);
                    return 0;
                }
                else
                    return(insertarSufijo(ab,lit)); /*si se pudo mover sigue buscando la posici�n para insertarlo*/
                break;

        case 2: AB_MoverCte(&ab,DER,&error); /*si es 2 es un operador ninario trata PRIMERO moverse a la der*/
                if (error) /*si no pudo moverlo lo inserta ah�*/
                {
                    AB_Insertar(&ab,DER,&lit,&error);
                    return 0;
                }
                else
                    cambiorama=insertarSufijo(ab,lit); /*en cambio sin� sigue buscando*/
                if (cambiorama==1) /*si cambio rama es igual a 1 TODA LA RAMA DE LA DERECHA ESTA OCUPADA ENTONCES TIENE QUE IR A BUSCAR A LA IZQ DEL CTE un lugar*/
                    {
                        AB_MoverCte(&ab,PAD,&error); /*mueve al padre*/
                        AB_MoverCte(&ab,IZQ,&error); /*mueve a la izq*/
                        if (error) /*si no pudo moverse inserta a la izq*/
                        {
                            AB_Insertar(&ab,IZQ,&lit,&error);
                            return 0;
                        }
                        else
                            return(insertarSufijo(ab,lit)); /*sino sigue buscando*/
                    }
                 break;
        default:
            return 1;
    }

    return 1;
}

int Expresion_Crear(TExpresion* expr) {
    AB_Crear(&expr->ABExp,sizeof(TLiteral));
    return RES_OK;
}



int Expresion_Parsear(TExpresion* expr,const char* string,const char* var)
{
    TPila sufijo;
    TLiteral lit;
    int error;

    P_Crear(&sufijo,sizeof(TLiteral));
	infijo_a_sufijo(string,var,&sufijo);
	P_Sacar(&sufijo,&lit);
	AB_Insertar(&expr->ABExp,RAIZ,&lit,&error);
	while (!P_Vacia(sufijo))
	{
	    P_Sacar(&sufijo,&lit);
	    insertarSufijo(expr->ABExp,lit);
	}



    return RES_OK;
}


int Expresion_Derivar(const TExpresion* expr,TExpresion* deriv) {
	int error;
	TLiteral lit;
	TAB origen;

	origen = expr->ABExp;

	AB_MoverCte(&origen,RAIZ,&error); /* quiero derivar todo el arbol de expresión */

	if (error)
		return 0; /* no se pudo mover */

	AB_ElemCte(origen,&lit);

	if (Literal_Derivar(&lit, &origen, &deriv->ABExp))
		return RES_OK;

	return ERROR; /* no pudo derivar */
}

int Expresion_Simplificar(const TExpresion* expr,TExpresion* simpl) {
	int error;
	TLiteral lit;
	TAB origen;

	origen = expr->ABExp;

	AB_MoverCte(&origen,RAIZ,&error); /* quiero simplificar todo el arbol de expresión */

	if (error)
		return ERROR; /* no se pudo mover */

	AB_ElemCte(origen,&lit);
    if (Literal_Simplificar(&lit, &origen, &simpl->ABExp))
		return RES_OK;

	return ERROR; /* no pudo simplificar */
}

void copio_al_string(char *nodostring, char **string){

	char *nuevoString;
	/*con realloc se complicaba, lo hice así, y funciona igual.*/
	if (nodostring[0] != '\0'){/*si es cos, ln o sen, se le agrega un paréntesis adelante y atrás de su argumento*/
		if ((strcmp(nodostring, "cos")== 0)||(strcmp(nodostring, "sin")== 0)||(strcmp(nodostring, "ln")== 0)){
			nuevoString = (char *) malloc ((strlen(nodostring)+strlen(*string)+2)* sizeof (char));
			sprintf(nuevoString, "%s%s(", *string, nodostring);
		}else{

			nuevoString = (char *) malloc ((strlen(nodostring)+strlen(*string)+1)* sizeof (char));
			sprintf(nuevoString, "%s%s", *string, nodostring);
		}

		free(*string); /*libero el viejo string*/
		*string = nuevoString; /*asigno el nuevo al viejo*/

	}

}


void aStringEnOrden(TAB exprcpy, int MOV, char** string){
	TLiteral nodo;
	int error;
	char *nodoString = NULL;
	char *nuevoString;

	AB_MoverCte(&exprcpy, MOV, &error);

	if (!error)
	{
		aStringEnOrden(exprcpy, IZQ, string);
		AB_ElemCte(exprcpy,&nodo);
		Literal_AString(&nodo,&nodoString);

		copio_al_string(nodoString, string);

		aStringEnOrden(exprcpy, DER, string);

		/*de este modo se agrega el paréntesis final a las funciones cos, sen y ln*/
		if ((strcmp(nodoString, "cos")== 0)||(strcmp(nodoString, "sin")== 0)||(strcmp(nodoString, "ln")== 0)){
			nuevoString = (char *) malloc ((strlen(nodoString)+strlen(*string)+2)* sizeof (char));
			sprintf(nuevoString, "%s)", *string);
			free(*string);
			*string = nuevoString;
		}

	}


}


int Expresion_AString(const TExpresion *expr, char** string) {
	int error;
	TAB exprAux;
	int tamanio=1;

	exprAux = expr->ABExp; /*Copio el árbol expresión*/

    *string = (char *) malloc(tamanio * sizeof(char));
    *string[0]='\0';

   	AB_MoverCte(&exprAux,RAIZ,&error); /*muevo el cte a la raíz*/

	if(!error){

		aStringEnOrden(exprAux, RAIZ, string);

	}else{
			return ERROR; /*árbol vacio*/
	}

	return RES_OK;
}


void Expresion_Destruir(TExpresion* expr) {
   BorrarLiteral(expr->ABExp,RAIZ);
   AB_Vaciar(&expr->ABExp);
}
